import requests
import socket
import urllib.parse
from typing import Optional, Dict, Any
from pathlib import Path

class NetworkUtils:
    """网络操作工具类，处理所有网络相关的操作"""
    
    DEFAULT_TIMEOUT = 10  # 默认超时时间(秒)
    
    @staticmethod
    def is_connected() -> bool:
        """检查网络连接是否可用"""
        try:
            # 尝试连接到一个可靠的公共DNS服务器
            socket.create_connection(("8.8.8.8", 53), timeout=5)
            return True
        except OSError:
            return False
    
    @staticmethod
    def download_file(
        url: str, 
        save_path: Union[str, Path], 
        headers: Optional[Dict[str, str]] = None,
        timeout: int = DEFAULT_TIMEOUT
    ) -> bool:
        """
        下载文件到指定路径
        :param url: 文件URL
        :param save_path: 保存路径
        :param headers: 请求头
        :param timeout: 超时时间(秒)
        :return: 是否成功
        """
        try:
            response = requests.get(
                url, 
                headers=headers or {}, 
                stream=True, 
                timeout=timeout
            )
            response.raise_for_status()
            
            with open(save_path, 'wb') as f:
                for chunk in response.iter_content(chunk_size=8192):
                    if chunk:  # 过滤掉保持连接的新块
                        f.write(chunk)
            return True
        except (requests.RequestException, IOError) as e:
            print(f"下载文件失败: {e}")
            return False
    
    @staticmethod
    def fetch_json(
        url: str, 
        params: Optional[Dict[str, Any]] = None,
        headers: Optional[Dict[str, str]] = None,
        timeout: int = DEFAULT_TIMEOUT
    ) -> Optional[Dict[str, Any]]:
        """
        获取JSON数据
        :param url: API URL
        :param params: 查询参数
        :param headers: 请求头
        :param timeout: 超时时间(秒)
        :return: JSON数据或None
        """
        try:
            response = requests.get(
                url, 
                params=params, 
                headers=headers or {}, 
                timeout=timeout
            )
            response.raise_for_status()
            return response.json()
        except (requests.RequestException, ValueError) as e:
            print(f"获取JSON数据失败: {e}")
            return None
    
    @staticmethod
    def get_radio_stream_url(base_url: str, station_id: str) -> str:
        """
        构建电台流媒体URL
        :param base_url: 基础URL
        :param station_id: 电台ID
        :return: 完整的流媒体URL
        """
        # 对station_id进行URL编码
        encoded_id = urllib.parse.quote(station_id)
        return f"{base_url.rstrip('/')}/{encoded_id}"
    
    @staticmethod
    def check_stream_available(stream_url: str, timeout: int = 5) -> bool:
        """
        检查流媒体是否可用
        :param stream_url: 流媒体URL
        :param timeout: 超时时间(秒)
        :return: 是否可用
        """
        try:
            # 发送HEAD请求检查流媒体可用性
            response = requests.head(
                stream_url, 
                timeout=timeout,
                allow_redirects=True
            )
            return response.status_code == 200
        except requests.RequestException:
            return False
    
    @staticmethod
    def get_public_ip() -> Optional[str]:
        """获取公网IP地址"""
        try:
            response = requests.get('https://api.ipify.org?format=json', timeout=5)
            return response.json().get('ip')
        except (requests.RequestException, ValueError, KeyError):
            return None